package ks.client.ipc;

import ks.framework.common.Message;
import ks.framework.common.network.CommunicationAgent;
import ks.framework.debug.Debug;
/**
 * The Reader class is responsible for interpreting all communication from the
 * server.
 * 
 * It executes in its own thread and communicates all messages back to 
 * a Processor.
 * 
 * @author George T. Heineman (heineman@cs.wpi.edu)
 */

class Reader implements Runnable {
	/** Input agent. */
	private CommunicationAgent agent;
	
	/** Client to whom we direct our actions. */
	Client client;
	
	/** Our own thread of control. */
	private Thread thread = null;

	
	/** Construct reader with Talker in mind. */ 
	public Reader(CommunicationAgent agent, Client client) {
		this.client = client;
		this.agent = agent;
	}

	/**
	 * This thread waits for any input generated by Talker's behavior with the
	 * Server.
	 * 
	 * There may be problems when disconnecting since two threads are in
	 * contention for the serverOutput object stream (see readLine in Talker).
	 */
	public void run() {
		try {
			// The very first thing we read is going to be the initial ACK
			// Block waiting for any response from the server.
			Debug.println ("Client reader waiting to read LOGIN ACK");
			Message m = (Message) agent.readObject();
			
			// deal with this ACK specially.
			if (!m.getName().equals("ack")) {
				System.err.println("Received: " + m + " instead of ACK from server.");
				return;
			}
			
			// have client know about this request.
			client.process (m);
			
			while (true) {
				// Block waiting for any response from the server.
				Debug.println ("Client reader waiting to read");
				m = (Message) agent.readObject();
	
				// if null, the server has shut down.
				if (m == null)
					break;
				
				// Have ClientInterface process the request. This is done to avoid reader
				// from having to know the entity who instantiated it.
				client.process (m);
			}
		} catch (RuntimeException re) {
			re.printStackTrace();
			Debug.println ("Exiting reader.");
		}
		
		// terminate.
		agent.close();
		client.connected(false);
	}

	/**
	 * Start the thread off as a Daemon thread.
	 */
	public void start() {
		if (thread == null) {
			Debug.println ("Client reader starting");
			thread = new Thread(this);
			thread.setDaemon(true);
			thread.start();
		}
	}
}